package com.ns.attendance.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.jdbc.Work;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate4.HibernateCallback;
import org.springframework.orm.hibernate4.support.HibernateDaoSupport;

/**
 * dao的模版方法
 * @author Han
 */
@SuppressWarnings("unchecked")
public class BaseDao<T, ID extends Serializable> extends HibernateDaoSupport {

	protected Class<T> entityClass;

	public BaseDao() {
	}

	protected Class getEntityClass() {
		if (entityClass == null) {
			entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		}
		return entityClass;
	}

	
	public void saveOrUpdate(T t) {
		getHibernateTemplate().saveOrUpdate(t);
	}

	
	public Serializable save(T t) {
		return getHibernateTemplate().save(t);
	}

	
	public void update(T t) {
		getHibernateTemplate().update(t);
	}

	
	public T load(ID id) {
		return (T) getHibernateTemplate().load(getEntityClass(), id);
	}

	
	public T get(ID id) {
		return (T) getHibernateTemplate().get(getEntityClass(), id);
	}

	
	public boolean contains(T t) {
		return getHibernateTemplate().contains(t);
	}

	
	public void delete(T t) {
		getHibernateTemplate().delete(t);
	}

	
	public void deleteAll(Collection<T> entities) {
		getHibernateTemplate().deleteAll(entities);
	}

	
	public List<T> find(String queryString, Object ...values) {
		return (List<T>) getHibernateTemplate().find(queryString, values);
	}
	
	
	public List<T> findAll(){
		return (List<T>) getHibernateTemplate().find("from "+getEntityClass().getCanonicalName());
	}
	
	public int excuteHqlUpdate(final String hql,final Object ...params){
		return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<Integer>() {
			@Override
			@SuppressWarnings("unchecked")
			public Integer doInHibernate(Session session) throws HibernateException {
				Query queryObject = session.createQuery(hql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						queryObject.setParameter(i, params[i]);
					}
				}
				return queryObject.executeUpdate();
			}
		});
	}
	
	public int excuteSqlUpdate(final String sql,final Object ...params){
		return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<Integer>() {
			@Override
			@SuppressWarnings("unchecked")
			public Integer doInHibernate(Session session) throws HibernateException {
				SQLQuery queryObject = session.createSQLQuery(sql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						queryObject.setParameter(i, params[i]);
					}
				}
				return queryObject.executeUpdate();
			}
		});
	}
	
	public List<T> findBySql(final String sql,final Object ...params){
		final String entityName = getEntityClass().getCanonicalName();
		return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<List<T>>() {
			@Override
			@SuppressWarnings("unchecked")
			public List<T> doInHibernate(Session session) throws HibernateException {
				SQLQuery queryObject = session.createSQLQuery(sql);
				queryObject.addEntity(entityName);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						queryObject.setParameter(i, params[i]);
					}
				}
				return queryObject.list();
			}
		});
	}
	
	public List<Object> findObjectBySql(final String sql,final Object ...params){
		return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<List<Object>>() {
			@Override
			@SuppressWarnings("unchecked")
			public List<Object> doInHibernate(Session session) throws HibernateException {
				SQLQuery queryObject = session.createSQLQuery(sql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						queryObject.setParameter(i, params[i]);
					}
				}
				return queryObject.list();
			}
		});
	}
	
	public List<Object> findObjectByHql(final String hql,final Object ...params){
		return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<List<Object>>() {
			@Override
			@SuppressWarnings("unchecked")
			public List<Object> doInHibernate(Session session) throws HibernateException {
				Query queryObject = session.createQuery(hql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						queryObject.setParameter(i, params[i]);
					}
				}
				return queryObject.list();
			}
		});
	}
	/**
	 * 查找不被hibernate管理的实体
	 * @param sql
	 * @param clazz
	 * @param params
	 * @return
	 */
	public <T> List<T> findToTransformerBySql(final String sql,final Class<T> clazz,final  Object ...params) {
		return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<List>() {
			@Override
			@SuppressWarnings("unchecked")
			public List doInHibernate(Session session) throws HibernateException {
				SQLQuery queryObject = session.createSQLQuery(sql);
				if(clazz == null || clazz == Map.class){
					queryObject.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
				}else{
					queryObject.setResultTransformer(Transformers.aliasToBean(clazz));
				}
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						queryObject.setParameter(i, params[i]);
					}
				}
				return queryObject.list();
			}
		});
	};
	
	
	/**
	 * 批处理一条sql
	 * 
	 * @param sql
	 * @param params
	 * @return
	 */
	public int excuteBatchSqlUpdate(final String sql, final List<Object[]> params) {
		return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<Integer>() {
			@Override
			@SuppressWarnings("unchecked")
			public Integer doInHibernate(Session session) throws HibernateException {
				//这个需要自己控制事务，和spring兼容不好
//				Connection connection = null;
//				try {
//					connection = SessionFactoryUtils.getDataSource(getSessionFactory()).getConnection();
//					connection.setAutoCommit(false);
//					PreparedStatement statement = connection.prepareStatement(sql);
//					int index = 0;
//					for (Object[] objs : params) {
//						for (int i = 0; i < objs.length; i++) {
//							statement.setObject(i+1, objs[i]);
//						}
//						statement.addBatch();
//						index++;
//						if(index%100 == 0){
//							statement.executeBatch();
//							statement.clearBatch();
//						}
//					}
//					statement.executeBatch();
//					return 1;
//				} catch (SQLException e) {
//					e.printStackTrace();
//					try {
//						connection.rollback();
//					} catch (SQLException e1) {
//						e1.printStackTrace();
//					}
//					return 0;
//				}
				session.doWork(new Work() {
					@Override
					public void execute(Connection connection) throws SQLException {
						PreparedStatement statement = connection.prepareStatement(sql);
						int index = 0;
						for (Object[] objs : params) {
							for (int i = 0; i < objs.length; i++) {
								statement.setObject(i+1, objs[i]);
							}
							statement.addBatch();
							index++;
							if(index%100 == 0){
								statement.executeBatch();
								statement.clearBatch();
							}
						}
						statement.executeBatch();
					}
				});
				return 1;
			}
		});
	}

	
	
	
	public void refresh(T t) {
		getHibernateTemplate().refresh(t);
	}
	//可以在xml上写  default-autowire="byName"来省去下面的代码
	@Autowired
	public void setHibernateSessionFactory(SessionFactory sessionFactory){
		super.setSessionFactory(sessionFactory);
	}
	
}
